/*
 * IAPaymentProcessingManagerBean.java
 */
package managedbean;

import com.paypal.sdk.core.nvp.NVPDecoder;
import com.paypal.sdk.core.nvp.NVPEncoder;
import com.paypal.sdk.profiles.APIProfile;
import com.paypal.sdk.profiles.ProfileFactory;
import com.paypal.sdk.services.NVPCallerServices;
import entity.TouristAccountEntity;
import entity.PaymentManagementEntity;
import entity.ReservationEntity;
import entity.StakeholderEntity;
import entity.TransactionsEntity;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import session.stateful.TouristSessionBean;
import session.stateful.ReservationSessionBean;
import session.stateful.TransactionSessionBean;
import session.stateful.PayPalSessionBean;
import session.stateless.PaymentProcessingSessionBeanRemote;
//import session.stateless.PaymentProcessingSessionBeanRemote;

/**
 *
 * @author IS3102 ES4
 */
@ManagedBean(name = "iAPaymentProcessingManagerBean")
@SessionScoped
public class IAPaymentProcessingManagerBean {

    @EJB
    private PaymentProcessingSessionBeanRemote ppsbr;
    @EJB
    private TransactionSessionBean transactionSessionBean;
    @EJB
    private TouristSessionBean touristSessionBean;
    @EJB
    private ReservationSessionBean reservationSessionBean;
//    @EJB 
//    private PayPalSessionBean payPalSessionBean;
    private String cardType;
    private Collection<String> cardTypeList = new ArrayList<String>();
    private String cardNumber;
    private String expMonth;
    private Collection<String> expMonthList = new ArrayList<String>();
    private Collection<String> expYearList = new ArrayList<String>();
    private String expYear;
    private String cvv;
    private String hostIp;
    private Long paymentId;
    private TouristAccountEntity selectedTourist;
    private StakeholderEntity selectedStakeholder;
    private ReservationEntity selectedReservation;
    private PaymentManagementEntity selectedPaymentManagement;
    private FacesContext ctx = FacesContext.getCurrentInstance();
    //by Khanh Vu
    private String purpose;
    private double paymentAmount;

    /** Creates a new instance of IAPaymentProcessingManagerBean */
    public IAPaymentProcessingManagerBean() {
        selectedStakeholder = (StakeholderEntity) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("stakeholder");
        //System.out.println("email"+ selectedStakeholder.getCorpEmail());
        createCardTypeList();
        createExpMonthList();
        createExpYearList();
    }

    public void initPaymentProcessing(PhaseEvent event) {
//        selectedTourist= touristSessionBean.getTouristById(Long.valueOf("111"));
//        selectedReservation= reservationSessionBean.getReservationById(Long.valueOf("111"));
        System.out.println("Test abc");
        selectedTourist = (TouristAccountEntity) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("tourist");
        selectedReservation = (ReservationEntity) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("selectedReservation");
        //by Khanh Vu
        purpose = (String) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("purpose");
        //end by Khanh Vu
        if (purpose.equals("payCurrentBill")) {
            selectedPaymentManagement = transactionSessionBean.getCurrentBill(selectedStakeholder);
        } else if (purpose.equals("changeReservation") || purpose.equals("makeReservation")) {
            paymentAmount = (Double) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("amountPaid");
        }
    }
//    public void payment() throws IOException {
//        if (getEmail() == null) {
//            // user not logged in
//            FacesContext.getCurrentInstance().getExternalContext().redirect("https://" + getHostIp() + ":8080/IS3102Project-war/endPay.xhtml");
//        }
//    }

    public void createCardTypeList() {
        this.getCardTypeList().add("MasterCard");
        this.getCardTypeList().add("Visa");
        this.getCardTypeList().add("Discover");
    }

    public void createExpMonthList() {
        this.getExpMonthList().add("01");
        this.getExpMonthList().add("02");
        this.getExpMonthList().add("03");
        this.getExpMonthList().add("04");
        this.getExpMonthList().add("05");
        this.getExpMonthList().add("06");
        this.getExpMonthList().add("07");
        this.getExpMonthList().add("08");
        this.getExpMonthList().add("09");
        this.getExpMonthList().add("10");
        this.getExpMonthList().add("11");
        this.getExpMonthList().add("12");
    }

    public void createExpYearList() {

        Date today = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        Integer curYear = Integer.parseInt(sdf.format(today));

        for (int i = 0; i < 20; i++) {
            this.getExpYearList().add(String.valueOf(curYear + i));
        }
    }

//[PAYMENT]----------------------------------------------------------------------------------------------
    public NVPDecoder DoDirectPaymentCode(String paymentAction, String amount, String cardType,
            String acct, String expdate, String cvv2, String email,
            String firstName, String lastName) {
        NVPEncoder encoder = new NVPEncoder();
        NVPDecoder decoder = new NVPDecoder();

        try {

            NVPCallerServices caller = new NVPCallerServices();
            APIProfile profile = ProfileFactory.createSignatureAPIProfile();

            // Set up your API credentials, PayPal end point, API operation and version.
            profile.setAPIUsername("web_1316757704_biz_api1.gmail.com");
            profile.setAPIPassword("1316757754");
            profile.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AobkBjpaOfK5wRRDT34RrVAP6RfZ");
            profile.setEnvironment("sandbox");
            profile.setSubject("");
            caller.setAPIProfile(profile);

            encoder.add("VERSION", "60.0");
            encoder.add("METHOD", "DoDirectPayment");

            // Add request-specific fields to the request string.
            encoder.add("PAYMENTACTION", paymentAction);
            encoder.add("AMT", amount);
            encoder.add("CREDITCARDTYPE", cardType);
            encoder.add("ACCT", acct);
            encoder.add("EXPDATE", expdate);
            encoder.add("CVV2", cvv2);
            encoder.add("PAYER", email);
            encoder.add("FIRSTNAME", firstName);
            encoder.add("LASTNAME", lastName);

            // Execute the API operation and obtain the response.
            String NVPRequest = encoder.encode();
            String NVPResponse = (String) caller.call(NVPRequest);
            decoder.decode(NVPResponse);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return decoder;
    }

    public void usePayPal() throws IOException {
        System.out.println("Begin use paypal");
        String firstName = null;
        String lastName = null;
        String email = null;
        String salesAmt = null;
        String expDate = "" + expMonth + expYear;
        String paypalTransactionId = null;
        String paypalCorrelationId = null;
        org.apache.log4j.BasicConfigurator.configure();
        System.out.println("123");
        if (selectedStakeholder != null) {
            System.out.println("get stakeholder");
            firstName = getSelectedStakeholder().getCorpName();
            lastName = getSelectedStakeholder().getCorpContactPerson();
            email = getSelectedStakeholder().getCorpEmail();
        } else {
            System.out.println("begin use tourist");
            firstName = selectedTourist.getTourist().getFirstName();
            lastName = selectedTourist.getTourist().getLastName();
            email = selectedTourist.getTourist().getEmail();
        }
        System.out.println("Step 1");

        if (purpose.equals("payCurrentBill")) {
            salesAmt = String.valueOf(getSelectedPaymentManagement().getOutstandingBilling());
        } //By Khanh Vu               
        else if (purpose.equals("changeReservation") || purpose.equals("makeReservation")) {
            salesAmt = (Double) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("amountPaid") + "";
        }
        //End by Khanh Vu
        System.out.println("Step 2");
        NVPDecoder paypalResponse = DoDirectPaymentCode("Sale", salesAmt, cardType, cardNumber,
                expDate, cvv, email, firstName, lastName);

        // ack variable
        boolean success = false;
        String response = "";
        String statusMessage = "";

        for (Object objKey : paypalResponse.getMap().keySet()) {
            System.out.println(objKey.toString() + " = " + paypalResponse.getMap().get(objKey));

            if (objKey.toString().equals("L_LONGMESSAGE0")) {
                statusMessage = (String) paypalResponse.getMap().get(objKey);

                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Payment Result: " + statusMessage, ""));
            }
            System.out.println("Step 3");
            // Ack is a success
            if (objKey.toString().equals("ACK")) {
                response = (String) paypalResponse.getMap().get(objKey);
                if (response.equals("Success")) {
                    success = true;
                }
            }
            if (objKey.toString().equals("TRANSACTIONID")) {
                paypalTransactionId = (String) paypalResponse.getMap().get(objKey);
            }
            if (objKey.toString().equals("CORRELATIONID")) {
                paypalCorrelationId = (String) paypalResponse.getMap().get(objKey);
            }
        }

        // transaction successful
        if (success == true) {
            // create payment record
            //change by Khanh Vu
            //transactionSessionBean.updatePaymentManagement(selectedPaymentManagement);
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("paymentOutcome", "success");
            if (purpose.equals("changeReservation")) {
                changeReservation(salesAmt, "PAYMENT", paypalTransactionId, paypalCorrelationId,
                        selectedTourist, selectedReservation);
                String serverName = ctx.getExternalContext().getRequestServerName();
                int serverPort = (Integer) ctx.getExternalContext().getSessionMap().get("serverPort");
                String contextPath = ctx.getExternalContext().getRequestContextPath();
                ctx.getExternalContext().redirect("http://" + serverName + ":" + serverPort + contextPath + "/tourist/VisitorViewReservationInfo.xhtml");
            } else if (purpose.equals("makeReservation")) {
                makeReservation(salesAmt, "PAYMENT", paypalTransactionId, paypalCorrelationId,
                        selectedTourist);
                String serverName = ctx.getExternalContext().getRequestServerName();
                int serverPort = (Integer) ctx.getExternalContext().getSessionMap().get("serverPort");
                String contextPath = ctx.getExternalContext().getRequestContextPath();
                ctx.getExternalContext().redirect("http://" + serverName + ":" + serverPort + contextPath + "/tourist/VisitorConfirmReservation.xhtml");
            } else if (purpose.equals("payCurrentBill")) {
                createTransactionEntity(salesAmt, "PAYMENT", paypalTransactionId, paypalCorrelationId,
                        selectedTourist, selectedReservation, selectedStakeholder, selectedPaymentManagement, purpose);
            }
            //end change by Khanh Vu
            //TODO: Thai Duy is doing 
            //if (selectedPaymentManagement !=null)
            // go to success page, print receipt
            //FacesContext.getCurrentInstance().getExternalContext().redirect("http://" + getHostIp() + ":8080/IS3102Project-war/endPay.xhtml");
            {
            }
        } else {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("paymentOutcome", "fail");
        }
        cardNumber = "";
        cvv = "";
        expMonth = "";
        expYear = "";
    }

    public void createTransactionEntity(String amount, String description, String paypalTransactionId, String paypalCorrelationId,
            TouristAccountEntity tourist, ReservationEntity reservation, StakeholderEntity stakeholder,
            PaymentManagementEntity paymentManagement, String purpose) {
        transactionSessionBean.createTransaction(Double.valueOf(amount), description, paypalTransactionId, paypalCorrelationId,
                tourist, reservation, stakeholder, paymentManagement, purpose);
    }
    //Method by Khanh Vu

    public void changeReservation(String amount, String description, String paypalTransactionId, String paypalCorrelationId,
            TouristAccountEntity tourist, ReservationEntity reservation) {
        transactionSessionBean.createChangeReservationTransaction(Double.valueOf(amount), description, paypalTransactionId, paypalCorrelationId,
                tourist, reservation, purpose);
    }

    public void makeReservation(String amount, String description, String paypalTransactionId, String paypalCorrelationId,
            TouristAccountEntity tourist) {
        long id = transactionSessionBean.createMakeReservationTransaction(Double.valueOf(amount), description, paypalTransactionId, paypalCorrelationId,
                tourist, purpose);
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("transactionId", id);
    }
    //end method by Khanh Vu
//    public void testPaypalBean() throws IOException{
//        getPayPalSessionBean().usePayPal();
//    }

//[PAYMENT]------------------------------------------------------------------------------------------------
//[REFUND]-------------------------------------------------------------------------------------------------
    public NVPDecoder RefundTransactionCode(String refundType, String transactionId, String amount, String note) {
        NVPEncoder encoder = new NVPEncoder();
        NVPDecoder decoder = new NVPDecoder();
        NVPCallerServices caller = null;

        try {
            caller = new NVPCallerServices();
            APIProfile profile = ProfileFactory.createSignatureAPIProfile();
            /*
            WARNING: Do not embed plaintext credentials in your application code.
            Doing so is insecure and against best practices.
            Your API credentials must be handled securely. Please consider
            encrypting them for use in any production environment, and ensure
            that only authorized individuals may view or modify them.
             */

            // Set up your API credentials, PayPal end point, API operation and version.
            profile.setAPIUsername("web_1316757704_biz_api1.gmail.com");
            profile.setAPIPassword("1316757754");
            profile.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AobkBjpaOfK5wRRDT34RrVAP6RfZ");
            profile.setEnvironment("sandbox");
            profile.setSubject("");
            caller.setAPIProfile(profile);
            encoder.add("VERSION", "60.0");
            encoder.add("METHOD", "RefundTransaction");

            // Add request-specific fields to the request string.
            encoder.add("REFUNDTYPE", refundType);
            encoder.add("TRANSACTIONID", transactionId);
            if ((refundType != null) && (refundType.length() > 0) && (refundType.equalsIgnoreCase("Partial"))) {
                encoder.add("AMT", amount);
            }
            encoder.add("NOTE", note);

            // Execute the API operation and obtain the response.
            String NVPRequest = encoder.encode();
            String NVPResponse = (String) caller.call(NVPRequest);
            decoder.decode(NVPResponse);
        } catch (Exception ex) {

            ex.printStackTrace();
        }
        return decoder;
    }

    public void testRefund() throws IOException {
        selectedReservation = getReservationSessionBean().getReservationById(Long.valueOf("111"));
        String note;
        TransactionsEntity transaction;
        Double amount;

        transaction = selectedReservation.getTransactions().get(0);
        amount = selectedReservation.getDeposit() * 80 / 100;
        note = "soWhat?";
        refundPayPal(transaction, amount, note);
    }

    public void refundPayPal(TransactionsEntity transaction, Double amount, String note) throws IOException {
        String paypalTransactionId = null;
        String paypalCorrelationId = null;
        org.apache.log4j.BasicConfigurator.configure();

        paypalTransactionId = transaction.getPaypalTransactionId();
        NVPDecoder paypalResponse = RefundTransactionCode("Partial", paypalTransactionId, String.valueOf(amount), note);
        // ack variable
        boolean success = false;
        String response = "";
        String statusMessage = "";

        for (Object objKey : paypalResponse.getMap().keySet()) {
            System.out.println(objKey.toString() + " = " + paypalResponse.getMap().get(objKey));

            if (objKey.toString().equals("L_LONGMESSAGE0")) {
                statusMessage = (String) paypalResponse.getMap().get(objKey);

                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Payment Result: " + statusMessage, ""));
            }

            // Ack is a success
            if (objKey.toString().equals("ACK")) {
                response = (String) paypalResponse.getMap().get(objKey);
                if (response.equals("Success")) {
                    success = true;
                }
            }
            if (objKey.toString().equals("REFUNDTRANSACTIONID")) {
                paypalTransactionId = (String) paypalResponse.getMap().get(objKey);
            }
            if (objKey.toString().equals("CORRELATIONID")) {
                paypalCorrelationId = (String) paypalResponse.getMap().get(objKey);
            }
        }
        String serverName = ctx.getExternalContext().getRequestServerName();
        int serverPort = (Integer) ctx.getExternalContext().getSessionMap().get("serverPort");
        String contextPath = ctx.getExternalContext().getRequestContextPath();
        // transaction successful
        if (success == true) {
            // create payment record
            createTransactionEntity(String.valueOf(-1 * amount), "REFUND", paypalTransactionId, paypalCorrelationId,
                    transaction.getTourist(), transaction.getReservation(), transaction.getStakeholder(), transaction.getPaymentManagement(), purpose);
            System.out.println("Refund Successful");
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("paymentOutcome", "success");
            // go to success page, print receipt
            ctx.getExternalContext().redirect("http://" + serverName + ":" + serverPort + contextPath + "/endPay.xhtml");
        } else {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("paymentOutcome", "fail");
        }
    }
//[REFUND]---------------------------------------------------------------------------------------------------

    public String getCardType() {
        return cardType;
    }

    public void setCardType(String cardType) {
        this.cardType = cardType;
    }

    public Collection<String> getCardTypeList() {
        return cardTypeList;
    }

    public void setCardTypeList(Collection<String> cardTypeList) {
        this.cardTypeList = cardTypeList;
    }

    public String getCardNumber() {
        return cardNumber;
    }

    public void setCardNumber(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    public String getExpMonth() {
        return expMonth;
    }

    public void setExpMonth(String expMonth) {
        this.expMonth = expMonth;
    }

    public String getExpYear() {
        return expYear;
    }

    public void setExpYear(String expYear) {
        this.expYear = expYear;
    }

    public Collection<String> getExpMonthList() {
        return expMonthList;
    }

    public void setExpMonthList(Collection<String> expMonthList) {
        this.expMonthList = expMonthList;
    }

    public String getCvv() {
        return cvv;
    }

    public void setCvv(String cvv) {
        this.cvv = cvv;
    }

    public Collection<String> getExpYearList() {
        return expYearList;
    }

    public void setExpYearList(Collection<String> expYearList) {
        this.expYearList = expYearList;
    }

    public String getHostIp() throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getLocalHost();
        hostIp = inetAddress.getHostAddress();
        return hostIp;
    }

    public void setHostIp(String hostIp) {
        this.hostIp = hostIp;
    }

    public Long getPaymentId() {
        return paymentId;
    }

    public void setPaymentId(Long paymentId) {
        this.paymentId = paymentId;
    }

    public TouristAccountEntity getSelectedTourist() {
        return selectedTourist;
    }

    public void setSelectedTourist(TouristAccountEntity selectedTourist) {
        this.selectedTourist = selectedTourist;
    }

    public StakeholderEntity getSelectedStakeholder() {
        return selectedStakeholder;
    }

    public void setSelectedStakeholder(StakeholderEntity selectedStakeholder) {
        this.selectedStakeholder = selectedStakeholder;
    }

    public ReservationEntity getSelectedReservation() {
        return selectedReservation;
    }

    public void setSelectedReservation(ReservationEntity selectedReservation) {
        this.selectedReservation = selectedReservation;
    }

    public PaymentProcessingSessionBeanRemote getPpsbr() {
        return ppsbr;
    }

    public void setPpsbr(PaymentProcessingSessionBeanRemote ppsbr) {
        this.ppsbr = ppsbr;
    }

    public TransactionSessionBean getTransactionSessionBean() {
        return transactionSessionBean;
    }

    public void setTransactionSessionBean(TransactionSessionBean transactionSessionBean) {
        this.transactionSessionBean = transactionSessionBean;
    }

    public TouristSessionBean getTouristSessionBean() {
        return touristSessionBean;
    }

    public ReservationSessionBean getReservationSessionBean() {
        return reservationSessionBean;
    }

    public PaymentManagementEntity getSelectedPaymentManagement() {
        return selectedPaymentManagement;
    }

    public void setSelectedPaymentManagement(PaymentManagementEntity selectedPaymentManagement) {
        this.selectedPaymentManagement = selectedPaymentManagement;
    }
//
//    public PayPalSessionBean getPayPalSessionBean() {
//        return payPalSessionBean;
//    }

    public double getPaymentAmount() {
        return paymentAmount;
    }

    public void setPaymentAmount(double paymentAmount) {
        this.paymentAmount = paymentAmount;
    }
}
